package net.toby200.canalstoppages.scraper;

import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;

import net.toby200.canalstoppages.model.Location;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SuppressWarnings("ALL")
class JSoupNoticeDetailScraper {

	private static final Logger LOG = Logger.getLogger(JSoupNoticeDetailScraper.class.getName());
	
	private final Pattern locPattern = Pattern.compile("\\{\"start\":\\{\"lat\":\"(-?\\d*\\.?\\d*)\","
			+ "\"lng\":\"(-?\\d*\\.?\\d*)\"\\},"
			+ "\"end\":\\{\"lat\":\"(-?\\d*\\.?\\d*)\",\"lng\":\"(-?\\d*\\.?\\d*)\"\\}\\}");


	public NoticeDetail getNoticeDetail(String urlString) {
		return getNoticeDetail(urlString, 3);
	}
	

	NoticeDetail getNoticeDetail(String urlString, int retryCount) {
		Document doc;
		InputStream input = null;
		
		try {
			HttpRequest request = UrlFetchTransport.getDefaultInstance().createRequestFactory()				
					.buildGetRequest(new GenericUrl(urlString));
			HttpHeaders headers = request.getHeaders();
			headers.setUserAgent("CanalStoppages crawler toby@toby200.net");
			request.setHeaders(headers);
			input = request.execute().getContent();		
			
		} catch (Exception e) {
						
			if (retryCount > 0) {
				try {
					LOG.log(Level.INFO, "Attempt failed. Sleeping 2 seconds then retrying");
					Thread.sleep(2000);
				} catch (InterruptedException e1) {						
				}
                //noinspection AssignmentToMethodParameter
                return getNoticeDetail(urlString, --retryCount);
			} else {
				// no more retries
				LOG.log(Level.SEVERE, "Error getting notice detail from "  + urlString, e);
			}
		}
			
		if (input != null) {
			try {
				doc = Jsoup.parse(input, null, urlString);
				NoticeDetail detail = parseDoc(doc);
				return detail;
			} catch (Exception e) {
				LOG.log(Level.SEVERE, "Unable to parse detail page at " + urlString , e);
				LOG.log(Level.INFO, input.toString(), e);
			}
		}
		return  null;
	}
		

	NoticeDetail parseDoc(Document doc) {
		String type = null;		
		String description = null;
		String locationDetail = null;		
		Location startLoc = null;
		Location endLoc = null;

		NoticeDetail detail = null;
		
		// get location
		Elements javascript = doc.select("script[type=text/javascript]");
		String locString = "";
		for (Element element : javascript) {
			if (element.data().contains("var locations")) {
				locString = element.data();
			}
			
		}		
		Matcher m = locPattern.matcher(locString);
		if (m.find()) {
			try {
				String startLat = m.group(1);
				String startLng = m.group(2);
				String endLat = m.group(3);
				String endLng = m.group(4);
				startLoc = new Location(Double.parseDouble(startLat),
						Double.parseDouble(startLng));
				endLoc = new Location(Double.parseDouble(endLat),
						Double.parseDouble(endLng));
			} catch (NumberFormatException e) {
				LOG.log(Level.WARNING, "Invalid lat/long format", e);
			}
		}

		Element content = doc.select("div.standard-form").first();		
		type = content.getElementsContainingOwnText("Type:").first().nextElementSibling().text().trim();		
		
		locationDetail = content.select("fieldset").get(1).text().trim();
		Element locationEl = content.select("fieldset").get(1);
		locationDetail = locationEl.select("div").first().text();
		String from = "";
		String to = "";
		try {
			from = locationEl.select("div[class=value]").first().text().trim();
		} catch (Exception e) {
		}
		try {
			to =  locationEl.select("div[class=value]").get(1).text().trim();
		} catch (Exception e) {
		}
		if (from.equals(to)) {
			locationDetail = (locationDetail + " " + from).trim();
		} else {
			locationDetail = (locationDetail + " from " + from + " to " + to).trim();
		}
			
		description = content.getElementsContainingOwnText("Description:").first().nextElementSibling().text().trim();


	
		detail = new NoticeDetail(type, description, locationDetail, startLoc, endLoc);

		return detail;
	}
		
}
